<template>
  <div class="depart-tree">
    <el-popover
      ref="popover"
      placement="bottom"
      :width="width"
      trigger="click"
      @show="handleShow"
      @hide="handleHide"
    >
      <el-input
        placeholder="请输入关键字检索"
        clearable
        v-model="filterText">
      </el-input>
      <el-tree
        class="my-tree"
        ref="tree"
        :data="departments"
        default-expand-all
        show-checkbox
        node-key="id"
        size="small"
        :filter-node-method="filterNode"
        @check="handleCheckTree"
        :props="defaultProps"
      >
      </el-tree>
    </el-popover>
    <div class="tree-name" v-popover:popover>
      <div v-if="departNames && departNames.length">
        <span class="depName">
          {{ departNames[0].name }}
          <span class="name-del"><i class="el-icon-error" @click.stop="handleDelete(departNames[0].id)"/></span>
        </span>
        <span class="depName" v-if="departNames.length > 1">+ {{ departNames.length - 1 }}</span>
      </div>
      <div v-else class="no-tree-select">{{ placeholder || '请选择' }}</div>
      <span
        style="color: #c0c4cc; transition: all 0.5s"
        class="el-icon-arrow-down"
        :class="[isShow ? 'is-reverse' : '']"
      ></span>
    </div>
  </div>
</template>
<script>
/**
 * 多选状态下，严格的遵循父子互相关联的情况下
 * 参数说明
 * @isNodeParams 传入数据是否选中节点数据
 * eg:
 * [
 *   {
 *    id: 1,
 *    name: '张三',
 *    children: [{id: 1-1, name: '张三1'}]}
 * ] 目的是为了取树结构最后一级给后台，方便后台处理
 * @departments 树结构数据
 * @return 双向绑定 调用handleChange()
 */
export default {
  model: {
    prop: 'modelValue',
    event: 'change'
  },
  props: {
    modelValue: {
      type: Array,
      default: () => ([])
    },
    departments: {
      type: Array,
      default: () => ([])
    },
    width: {
      type: Number || String,
      default: 200
    },
    placeholder: {
      type: String,
      default: ''
    },
    isNodeParams: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    filterText (val) {
      this.$refs.tree.filter(val)
    },
    modelValue: {
      handler () {
        this.setPageViewValue()
      }
    },
    departments: {
      immediate: true,
      deep: true,
      handler () {
        this.setPageViewValue()
      }
    }
  },
  data: () => ({
    isShow: false,
    filterText: '',
    defaultProps: {
      children: 'children',
      label: 'name'
    },
    departNames: [],
    delIds: [],
    delKeys: []
  }),
  methods: {
    handleShow () {
      this.isShow = true
    },
    handleHide () {
      this.isShow = false
    },
    handleCheckTree () {
      this.departNames = this.$refs.tree.getCheckedNodes()
      this.handleChange()
    },
    setPageViewValue () {
      // 反显数据
      this.$nextTick(() => {
        if (this.modelValue?.length) {
          // props值为节点处理选中keys，当前isNodeParams：true 说明是节点传参
          let modelValue = this.isNodeParams ? this.modelValue.map(n => (n.id)) : this.modelValue
          let selectKeys = this.$refs.tree.getCheckedKeys()?.length ? this.$refs.tree.getCheckedKeys() : modelValue
          this.$refs.tree.setCheckedKeys(selectKeys)
          // 获取选中标签名字集合
          this.departNames = this.setDepartNames()
        } else {
          this.departNames = []
          this.$refs.tree.setCheckedKeys([])
        }
      })
    },
    handleDelete (id) {
      // 处理标签删除
      const checkNodes = this.$refs.tree.getCheckedNodes()
      // 获取全部选中keys集合
      const checkAllKeys = checkNodes.map(n => n.id)
      // 找到当前删除id所对应的对象
      const findDelNode = checkNodes.find(n => n.id === id)
      this.delKeys = [ findDelNode.id, ...this.setDeleteIds(id, findDelNode.children) ]
      // 去除要删除id保留剩下的
      let remainKeys = checkAllKeys.filter(n => !this.delKeys.includes(n))
      // 设置tree节点剩下选中值
      this.$refs.tree.setCheckedKeys(remainKeys)
      this.handleChange()
    },
    setDeleteIds (id, selectNodes) {
      if (selectNodes?.length) {
        selectNodes.forEach(n => {
          this.delIds.push(n.id)
          if (n?.children?.length) {
            this.setDeleteIds(id, n.children)
          }
        })
      }
      return this.delIds
    },
    handleChange () {
      if (this.isNodeParams) {
        this.$emit('change', this.$refs.tree.getCheckedNodes())
        return false
      }
      this.$emit('change', this.$refs.tree.getCheckedKeys())
    },
    setDepartNames () {
      // 处理输入框所需名字集合
      return this.$refs.tree.getCheckedNodes().map(n => ({
        id: n.id,
        name: n.name
      }))
    },
    filterNode (value, data) {
      if (!value) return true
      return data.name.indexOf(value) !== -1
    }
  }
}
</script>
<style lang="scss" scoped>
.depart-tree {
  .tree-name {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    cursor: pointer;
    padding: 0 15px;
    font-size: 12px;
    border: 1px solid #dcdfe6;
    border-radius: 16px;
    background-color: #fff;
    .depName {
      padding: 4px 8px;
      background: #f4f4f5;
      border-color: #e9e9eb;
      border-radius: 4px;
      color: #909399;
      margin-right: 8px;
      .name-del {
        color: #c0c4cc;
        &:hover {
          color: #909399;
        }
      }
    }
    .no-tree-select {
      font-size: 12px;
      color: #c0c4cc;
    }
  }
}
.my-tree {
  margin-top: 10px;
  max-height: 300px;
  overflow: auto;
  &::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }

  &::-webkit-scrollbar-thumb {
    background: rgba(144, 147, 153, 0.5);
    border-radius: 3px;
  }
}
.is-reverse {
  transform: rotateZ(-180deg);
}
</style>
